﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Services;
using System.IO;
using System.ServiceModel.Channels;
using System.Reflection;
using ADONETDataServicesExtension.Utils;
using ADONETDataServicesExtension.Providers;
using System.Text;
using System.Collections;
using ADONETDataServicesExtension.BLLUtils;

namespace ADONETDataServicesExtension
{
    public class DataService<T> : System.Data.Services.DataService<T>, IRequestHandler
    {
        private HttpContextServiceHost _host;

        private static readonly Type FrameworkType = typeof(System.Data.Services.DataService<T>);

        private CachedRequestParams RequestParams
        {
            get
            {
                return ReflectionHelper.Convert(ReflectionHelper.GetField(FrameworkType, "requestParams", this), frameworkValue => new CachedRequestParams(frameworkValue));
            }
            set
            {
                ReflectionHelper.SetField(FrameworkType, "requestParams", this, value == null ? null : value.FrameworkObject);
            }
        }

        private IDataService IDataService
        {
            get
            {
                return new IDataService(this);
            }
        }

        private IDataServiceProvider Provider
        {
            get
            {
                return ReflectionHelper.Convert(ReflectionHelper.GetField(FrameworkType, "provider", this), frameworkValue => new IDataServiceProvider(frameworkValue));
            }
            set
            {
                ReflectionHelper.SetField(FrameworkType, "provider", this, value == null ? null : value.FrameworkObject);
            }
        }

        private DataServiceConfiguration Configuration
        {
            get
            {
                return ReflectionHelper.Convert(ReflectionHelper.GetField<IDataServiceConfiguration>(FrameworkType, "configuration", this), frameworkValue => new DataServiceConfiguration(frameworkValue));
            }
            set
            {
                ReflectionHelper.SetField(FrameworkType, "configuration", this, value == null ? null : value.FrameworkObject);
            }
        }

        Message IRequestHandler.ProcessRequestForMessage(Stream messageBody)
        {
            if (!(this is IEFEntitiesEncapsulatedDataService))
                return ProcessRequestForMessage(messageBody);

            Message message2 = null;
            if (messageBody == null)
                throw new ArgumentNullException();
            _host = new HttpContextServiceHost(messageBody);
            AttachHost(_host);
            bool flag = true;
            try
            {
                EnsureProviderAndConfigForRequest();
                Action<Stream> writer = HandleRequest();
                Message message = CreateMessage(MessageVersion.None, "", ((IDataServiceHost)_host).ResponseContentType, writer, new IDataService(this));
                flag = false;
                message2 = message;
            }
            finally
            {
                if (flag)
                    new IDataService(this).DisposeDataSource();
            }
            return message2;
        }

        private void EnsureProviderAndConfigForRequest()
        {
            ReflectionHelper.InvokeVoidMethod(FrameworkType, "EnsureProviderAndConfigForRequest", this);
        }

        private static DataServiceConfiguration CreateConfiguration(Type dataServiceType, IDataServiceProvider provider, object dataSourceInstance)
        {
            DataServiceConfiguration configuration = new DataServiceConfiguration(provider);
            configuration.InvokeStaticInitialization(dataServiceType);
            configuration.RegisterCallbacks(dataServiceType);
            configuration.ApplyToProvider(dataSourceInstance);
            return configuration;
        }

        private Action<Stream> HandleRequest()
        {
            try
            {
                _host.VerifyQueryParameters();
                RequestDescription description = this.ProcessIncomingRequestUriAndCacheHeaders();
                if (description.TargetKind != RequestTargetKind.Batch)
                    return HandleNonBatchRequest(description);
                return HandleBatchRequest();
            }
            catch (Exception exception)
            {
                if (!exception.IsCatchableExceptionType())
                    throw;
                CachedRequestParams requestParams = RequestParams;
                string accept = (requestParams != null) ? requestParams.Accept : null;
                string acceptCharset = (requestParams != null) ? requestParams.AcceptCharset : null;
                return ErrorHandler.HandleBeforeWritingException(exception, new IDataService(this), accept, acceptCharset);
            }
        }

        private Action<Stream> HandleNonBatchRequest(RequestDescription description)
        {
            return ReflectionHelper.InvokeMethod<Action<Stream>>(FrameworkType, "HandleNonBatchRequest", this, description.FrameworkObject);
        }

        private Action<Stream> HandleBatchRequest()
        {
            return ReflectionHelper.InvokeMethod<Action<Stream>>(FrameworkType, "HandleBatchRequest", this);
        }

        private RequestDescription ProcessIncomingRequestUriAndCacheHeaders()
        {
            RequestParams = new CachedRequestParams(_host.RequestAccept, _host.RequestAcceptCharSet, _host.RequestContentType, _host.RequestHttpMethod, _host.RequestIfMatch, _host.RequestIfNoneMatch, _host.RequestVersion, _host.RequestMaxVersion, RequestUriProcessor.GetAbsoluteRequestUri(_host.FrameworkObject), RequestUriProcessor.GetServiceUri(_host.FrameworkObject));
            DataService<T>.ValidateRequest(RequestParams);
            return RequestUriProcessor.ProcessRequestUri(RequestParams.AbsoluteRequestUri, new IDataService(this));
        }

        private static void ValidateRequest(CachedRequestParams requestParams)
        {
            ReflectionHelper.InvokeStaticVoidMethod(typeof(System.Data.Services.DataService<T>), "ValidateRequest", requestParams.FrameworkObject);
        }

        private static Message CreateMessage(MessageVersion version, string action, string contentType, Action<Stream> writer, IDataService service)
        {
            return ReflectionHelper.InvokeStaticMethod<Message>(typeof(System.Data.Services.DataService<T>), "CreateMessage", version, action, contentType, writer, service.FrameworkObject);
        }
    }
}
